home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Gfx
/
Icon
/
itools_2.01.lha
/
icontools-2.01
/
opticon.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-06
|
18KB
|
710 lines
/* -*- C -*-
* OPTICON.C
*
* (c)Copyright 1994 by Tobias Ferber, ukjg@rz.uni-karlsruhe.de
*
* This file is part of the IconTools distribution
*
* OptIcon is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 1 of the License,
* or (at your option) any later version.
*
* OptIcon is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $VER: $Id: opticon.c,v 1.16 1995/08/06 20:39:35 tf Exp $ */
#include "version.h"
static char versiontag[] = "$VER: $Id: opticon.c,v 1.16 1995/08/06 20:39:35 tf Exp $";
/* Compile w/ -DDEBUG to output more information at runtime */
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/rdargs.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <workbench/icon.h>
#include "memfn.h"
#ifdef __GNUC__
/* suggest parentheses around assignment used as truth value */
#define if(assignment) if( (assignment) )
#endif /* __GNUC__ */
extern struct Library *OpenLibrary(STRPTR, ULONG);
extern void CloseLibrary(struct Library *);
extern void CopyMem(APTR, APTR, ULONG);
extern void *AllocMem(ULONG, ULONG);
extern void FreeMem(void *, ULONG);
extern ULONG TypeOfMem(void *);
extern struct RDArgs *ReadArgs(STRPTR, LONG *, struct RDArgs *);
extern LONG IoErr(void);
extern BOOL PrintFault(LONG, STRPTR);
extern BPTR Lock(STRPTR, LONG);
extern void UnLock(BPTR);
extern void FreeArgs(struct RDArgs *);
extern struct DiskObject *GetDiskObject(char *);
extern BOOL PutDiskObject(char *, struct DiskObject *);
extern void FreeDiskObject(struct DiskObject *);
struct IconBase *IconBase;
void display_version_information(void)
{
static char license[]=
"OptIcon is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published\n"
"by the Free Software Foundation; either version 1 of the License,\n"
"or (at your option) any later version.\n"
"\n"
"OptIcon is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with OptIcon; see the file COPYING. If not, write to the\n"
"Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
;
puts("\nOptIcon Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
"(c)Copyright 1994,95 by Tobias Ferber, ukjg@rz.uni-karlsruhe.de\n");
puts(license);
}
struct Image *free_image(struct Image *i)
{
if(i)
{
long size= i->Depth * i->Height * ((i->Width + 15) / 16) * sizeof(UWORD);
if(i->ImageData && size > 0)
FreeMem( i->ImageData, size );
FreeMem( i, sizeof(struct Image) );
}
return (struct Image *)0L;
}
/* command line options */
#define OPT_NOEXPAND (1<<0)
#define OPT_CRITICAL (1<<1)
#define OPT_VERBOSE (1<<2)
#define OPT_REMAPV37 (1<<3)
struct Image *optimize_image(struct Image *i, WORD planes, int optimode)
{
UWORD p16= i->Height * ((i->Width + 15) / 16); /* #of words per plane */
UWORD *idata= i->ImageData;
WORD d, dmax, D, P;
UBYTE pp= 0; /* plane pick */
UBYTE p10= 0; /* plane on/off */
struct Image *o= i; /* optimized image */
/* prevent silly args from being harmful */
if(!i)
return i;
if(planes > 8)
planes= 8;
if(optimode & OPT_VERBOSE)
{
printf("(depth=%d, pick=%d, onoff=%d)", i->Depth,
i->PlanePick,
i->PlaneOnOff);
fflush(stdout);
}
/*
PRESCAN: Examine dmax planes of i and compute
D = the real depth (without trailing 0 planes)
pp = the new PlanePick value
p10 = the new PlaneOnOff value
*/
dmax= (0 < planes && planes < i->Depth) ? planes : i->Depth;
for(d= D= 0; d<dmax; d++)
{
/* check if we have some image data for plane d */
if(i->PlanePick & (1<<d))
{
UWORD n, *p, v;
/* scan the image data of plane d */
for(n=0, p=idata, v=*p; n < p16; n++, p++)
if(*p != v)
break;
if(n==p16 && v==0xFFFF) /* plane d is entirely 1 */
p10 |= (1<<d); /* pp bit is already 0 */
if( n!=p16 || (n==p16 && v!=0x0000 && v!=0xFFFF) )
pp |= (1<<d);
if( n!=p16 || (n==p16 && v!=0x0000) )
D= d;
idata= &idata[p16];
}
else if(i->PlaneOnOff & (1<<d))
{
p10 |= (1<<d);
D=d;
}
}
++D;
if( (optimode & OPT_VERBOSE) && (D != dmax || pp != i->PlanePick || p10 != i->PlaneOnOff) )
{
printf(" -> (%d,%d,%d)", D,pp,p10);
fflush(stdout);
}
/* compute the #of planes in the output image */
P= ( planes>D && !(optimode & OPT_NOEXPAND) ) ? planes : D;
if(P != i->Depth || pp != i->PlanePick || p10 != i->PlaneOnOff)
{
UWORD p8= p16 * sizeof(UWORD);
UWORD *odata;
ULONG osize= P * p8;
if( o= (struct Image *)AllocMem(sizeof(struct Image),MEMF_CLEAR) )
{
if( odata= (UWORD *)AllocMem(osize,TypeOfMem(i->ImageData)|MEMF_CLEAR) )
{
CopyMem( (APTR)i, (APTR)o, sizeof(struct Image) );
o->ImageData= odata;
idata= i->ImageData;
for(d=0; d<D; d++)
{
if( pp & (1<<d) )
{
if(i->PlanePick & (1<<d))
{
CopyMem( (APTR)idata, (APTR)odata, p8 );
idata= &idata[p16];
odata= &odata[p16];
}
else /* !PlanePick bit (should not happen) */
{
memset( (char *)odata, (i->PlaneOnOff & (1<<d)) ? 0xFF : 0x00, p8 );
odata= &odata[p16];
}
}
else /* !pp bit */
{
if(i->PlanePick & (1<<d))
idata= &idata[p16];
if( !(optimode & OPT_CRITICAL) )
{
memset( (char *)odata, (p10 & (1<<d)) ? 0xFF : 0x00, p8 );
odata= &odata[p16];
pp |= (1<<d);
p10 &= ~(1<<d);
}
}
}
if(D>=3 && D<P) /* no need to check OPT_NOEXPAND sice P is < D if set */
{
UWORD *p;
if( p= (UWORD *)malloc(p8) )
{
if( (optimode & OPT_REMAPV37) && p10<=7 )
{
/*
REMAP: Make colors 4-7 become the last 4 in the palette
Algo: (1) OR together all planes > 2,
(2) invert the result,
(3) AND it with plane 2 and
(4) OR the result with all planes > 2
Note: There is no need to expand the image data if p10 &~ %111 != 0
*/
/* move to plane 2 */
idata= i->ImageData;
for(d=0; d<2; d++)
if(i->PlanePick & (1<<d))
idata= &idata[p16];
if(i->PlanePick & (1<<2))
{
memcpy((char *)p, (char *)idata, p8);
idata= &idata[p16];
}
else memset( (char *)p, (p10 & (1L<<2)) ? 0xFF : 0x00, p8 );
/* or planes 3..D, invert them, AND the result with plane 2 */
for(d=3; d<D; d++)
{
if(i->PlanePick & (1<<d))
{
memandnot( (char *)p, (char *)idata, p8 );
idata= &idata[p16];
}
/* else bit d of i->PlaneOnOff is 0 --> no-op */
}
/* move to plane 3 */
odata= o->ImageData;
for(d=0; d<3; d++)
if(pp & (1<<d))
odata= &odata[p16];
for(d=3; d<P; d++)
{
if( d>=D || pp & (1<<d) )
{
memor( (char *)odata, (char *)p, p8 );
odata= &odata[p16];
pp |= (1<<d);
}
}
}
else /* !REMAPV37 */
{
/*
EXPAND: Remap the last 4 colors of i to the last 4 colors of o
Algo: (1) OR together all planes but the last
(2) AND the result with the last plane
(3) set the result in all new planes
Note: if any plane of i but the last is entirely 1 then we can
simply copy the last plane of i to all new planes in o
*/
idata= i->ImageData;
if( p10 &~ (1<<(D-1)) == 0)
{
memset( (char *)p, 0x00, p8 );
for(d=0; d<D-1; d++)
{
if(i->PlanePick & (1<<d))
{
memor( (char *)p, (char *)idata, p8 );
idata= &idata[p16];
}
}
/* else plane d is entirely 0 */
if( i->PlanePick & (1<<(D-1)) )
memand( (char *)p, (char *)idata, p8 );
/* else the last plane is entirely 1 */
}
else /* move to the last plane */
{
for(d=0; d<D-1; d++)
if(i->PlanePick & (1<<d))
idata= &idata[p16];
if( i->PlanePick & (1<<(D-1)) )
memcpy( (char *)p, (char *)idata, p8 );
else
memset( (char *)p, 0xFF, p8 );
}
/* move to plane D */
odata= o->ImageData;
for(d=0; d<D; d++)
if(pp & (1<<d))
odata= &odata[p16];
for(d=D; d<P; d++)
{
memcpy( (char *)odata, (char *)p, p8 );
odata= &odata[p16];
pp |= (1<<d);
}
}
free(p);
}
else /* !p --> panic! */
{
FreeMem(o->ImageData,osize);
FreeMem(o,sizeof(struct Image));
o= (struct Image *)0L;
}
}
o->Depth= P;
o->PlanePick= pp;
o->PlaneOnOff= p10;
}
else /* !odata */
{
FreeMem(o,sizeof(struct Image));
o= (struct Image *)0L;
}
}
}
if(optimode & OPT_VERBOSE)
{
if(o && o!=i)
printf(" -> (%d,%d,%d)", o->Depth, o->PlanePick, o->PlaneOnOff);
putchar('\n');
}
return o;
}
/**/
static char *tackon(char *pname, char *fname)
{
char *buf= (char *)malloc(strlen(pname)+strlen(fname)+2);
if(buf)
{
register char *s= buf; *s= '\0';
if(pname)
{
register int n= 0;
while( *pname )
n++, *s++= *pname++;
if( n>0 && buf[n-1]!=':' && buf[n-1]!='/' )
*s++ = '/';
}
if(fname) while( *fname )
*s++ = *fname++;
*s= '\0';
}
return buf;
}
/* main, opticon(), and doall() share the following vars */
static char *whoami;
static LONG args[8] = { 0,0,0,0,0,0,0,0 };
WORD numplanes= 0;
int optiflags= 0;
int opticon(char *fname)
{
int rc= RETURN_OK;
/* We initially assume `fname' to be or to have an icon. */
char *iname= (char *)strdup(fname);
if(optiflags & OPT_VERBOSE)
printf("opticon `%s'\n",fname);
if(iname)
{
struct DiskObject *icon;
if( (icon= GetDiskObject(iname)) == NULL )
{
size_t x= strlen(iname) - 5;
if(x>0 && !stricmp(&(iname[x]),".info"))
{
iname[x]= '\0';
icon= GetDiskObject(iname);
}
}
if(icon)
{
struct Gadget *g= &icon->do_Gadget;
struct Image *ogr, *osr;
int modified= 0;
ogr= osr= (struct Image *)0L;
if(g->GadgetRender && (g->Flags & GFLG_GADGIMAGE))
{
struct Image *i= (struct Image *)g->GadgetRender;
if(optiflags & OPT_VERBOSE)
printf(" :normal "), fflush(stdout);
if( ogr= optimize_image(i,numplanes,optiflags) )
{
if(ogr != i)
{
g->GadgetRender= (APTR)ogr;
++modified;
}
else ogr= (struct Image *)0L; /* don't free ogr */
if(g->SelectRender && (g->Flags & GFLG_GADGHIMAGE))
{
i= (struct Image *)g->SelectRender;
if(optiflags & OPT_VERBOSE)
printf(" :selected "), fflush(stdout);
if( osr= optimize_image(i,numplanes, optiflags) )
{
if(osr != i)
{
g->SelectRender= (APTR)osr;
++modified;
}
else osr= (struct Image *)0L; /* don't free osr */
}
else
{
fprintf(stderr,"%s: %s.info: not enough free memory to optimize the selected image\n",whoami,iname);
rc= ERROR_NO_FREE_STORE;
}
}
}
else
{
fprintf(stderr,"%s: %s.info: not enough free memory to optimize the normal image\n",whoami,iname);
rc= ERROR_NO_FREE_STORE;
}
}
/* SMART/S */
if( rc == RETURN_OK && args[6] && (icon->do_Type == WBDRAWER || icon->do_Type == WBGARBAGE) )
{
BPTR lock= Lock(iname,ACCESS_READ);
if( BADDR(lock) )
UnLock(lock);
else
{
icon->do_Type = WBTOOL;
++modified;
}
}
if( modified && rc == RETURN_OK )
{
if( !PutDiskObject(iname,icon) )
PrintFault(rc= IoErr(), iname);
}
if(ogr) ogr= free_image(ogr);
if(osr) osr= free_image(osr);
FreeDiskObject(icon);
}
else /* !icon */
{
PrintFault(rc= IoErr(), iname);
fprintf(stderr,"%s: GetDiskObject() failed for %s[.info]\n",whoami,iname);
if(args[7])
rc= RETURN_OK; /* keep running */
}
free(iname);
}
else /* !iname */
{
fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
rc= ERROR_NO_FREE_STORE;
}
return rc;
}
int doall(char *pname)
{
int rc= RETURN_OK;
struct FileInfoBlock *fib= (struct FileInfoBlock *)AllocDosObject(DOS_FIB, NULL);
if(optiflags & OPT_VERBOSE)
printf("scanning `%s'\n",pname);
if(fib)
{
/* set to 1 if we are to call opticon(pname) after UnLock() */
int optme= 0;
BPTR lock= Lock(pname, ACCESS_READ);
if( BADDR(lock) )
{
if( Examine(lock,fib) )
{
/* not the initial call from main() for a file with ALL */
if( (optme= (fib->fib_DirEntryType > 0) ? 0:1) == 0 )
{
while( (rc==RETURN_OK) && ExNext(lock,fib) && (IoErr() != ERROR_NO_MORE_ENTRIES) )
{
char *pcat= tackon(pname,fib->fib_FileName);
if(pcat)
{
if(optiflags & OPT_VERBOSE)
printf("found `%s'\n",pcat);
if( fib->fib_DirEntryType > 0 ) /* directory */
{
rc= doall(pcat);
}
else /* file */
{
size_t x= strlen(pcat) - 5;
if( stricmp(&pcat[x],".info") == 0 ) /* "*.info" file */
{
rc= opticon(pcat);
}
}
free(pcat);
}
else /* !pcat */
{
fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
rc= ERROR_NO_FREE_STORE;
}
}
}
}
else PrintFault(rc= IoErr(), pname); /* Examine() failed */
UnLock(lock);
}
else optme= 1; /* !lock */
/*else PrintFault(rc= IoErr(), pname);*/
if(optme && rc==RETURN_OK)
rc= opticon(pname);
FreeDosObject(DOS_FIB,fib);
}
else /* !fib */
{
fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
rc= ERROR_NO_FREE_STORE;
}
return rc;
}
/**/
int main(int argc, char **argv)
{
struct RDArgs *a;
int rc= RETURN_OK;
whoami= *argv;
if( a= ReadArgs("FROM=NAME/A/M," /* 0 */
"DEPTH=PLANES/N," /* 1 */
"NOEXPAND/S," /* 2 */
"CRITICAL/S," /* 3 */
"REMAPV37/S," /* 4 */
"VERBOSE/S," /* 5 */
"SMART/S," /* 6 */
"ALL/S", /* 7 */
args, NULL) )
{
char **flist= (char **)args[0];
if(args[1])
{
if( (numplanes= (WORD)*(LONG *)(args[1])) < 1 )
{
fprintf(stderr,"%s: Illegal maximum depth %d\n",whoami,numplanes);
rc= RETURN_FAIL;
}
}
if(flist && rc == RETURN_OK)
{
if( IconBase= (struct IconBase *)OpenLibrary(ICONNAME,36) )
{
if(args[2]) optiflags |= OPT_NOEXPAND;
if(args[3]) optiflags |= OPT_CRITICAL;
if(args[4]) optiflags |= OPT_REMAPV37;
if(args[5]) optiflags |= OPT_VERBOSE;
for(;*flist && rc == RETURN_OK;flist++)
rc= args[7] ? doall(*flist) : opticon(*flist);
CloseLibrary((struct Library *)IconBase);
}
else
{
fprintf(stderr,"%s: You need %s V36+",whoami,ICONNAME);
rc= RETURN_ERROR;
}
}
FreeArgs(a);
}
else /* !ReadArgs */
{
if(argc == 1)
display_version_information();
else
PrintFault(rc= IoErr(),NULL);
}
return rc;
}